package com.rede.didiok.user.modulelist.pay.manager.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rede.didiok.common.constant.conf.SysConf;
import com.rede.didiok.common.constant.global.Constants;
import com.rede.didiok.common.domainEvent.EventAction;
import com.rede.didiok.common.dto.pay.PayOrderDto;
import com.rede.didiok.common.enums.*;
import com.rede.didiok.common.exception.exceptionType.BusinessException;
import com.rede.didiok.common.exception.exceptionType.InsertException;
import com.rede.didiok.common.exception.exceptionType.QueryException;
import com.rede.didiok.common.feign.RankFeignClient;
import com.rede.didiok.common.holder.RequestHolder;
import com.rede.didiok.common.schema.ProductDto;
import com.rede.didiok.common.schema.ProductRequest;
import com.rede.didiok.common.utils.DateUtils;
import com.rede.didiok.common.utils.JsonUtils;
import com.rede.didiok.common.utils.ResultUtil;
import com.rede.didiok.common.utils.StringUtils;
import com.rede.didiok.common.utils.business.DomainEventUtil;
import com.rede.didiok.common.utils.business.IdGenerator;
import com.rede.didiok.user.modulelist.pay.entity.PayOrderEntity;
import com.rede.didiok.user.modulelist.pay.factory.PayServiceFactory;
import com.rede.didiok.user.modulelist.pay.global.SQLConf;
import com.rede.didiok.user.modulelist.pay.manager.TradeManager;
import com.rede.didiok.user.modulelist.pay.model.bean.LanTuWxPayBean;
import com.rede.didiok.user.modulelist.pay.model.vo.BuyVO;
import com.rede.didiok.user.modulelist.pay.model.vo.SponsorVO;
import com.rede.didiok.user.modulelist.pay.service.PayOrderService;
import com.rede.didiok.user.modulelist.pay.utils.LantuPayUtil;
import com.rede.didiok.user.modulelist.rank.entity.RankMemberEntity;
import com.rede.didiok.user.modulelist.rank.service.RankMemberService;


/**
 * 订单管理模块
 * 他负责 业务怎么做
 * manager 负责 把service里涉及多表的拆出来 放在这里处理
 * service 是具体的业务实现 db操作 一般是单表业务操作
 *
 * @author 遇见
 */
@Service(value = "tradeManager")
@Slf4j
public class TradeManagerImpl implements TradeManager {

    @Resource
    private RankFeignClient rankFeignClient;
    @Resource
    private RankMemberService rankMemberService;
    @Resource
    private PayOrderService payOrderService;
    @Resource
    private DomainEventUtil domainEventUtil;
    @Autowired
    private IdGenerator idGenerator;
    @Resource
    private LanTuWxPayBean lanTuWxPayBean;

    //蓝兔支付成功后的回调url
    private static final String LANTU_NOTIFY_URL = "/trade/lantuWxPay/callback";


    @Transactional(rollbackFor = Exception.class)
    @Override
    public String buyNow(BuyVO buyVO) {
        Integer applyType = buyVO.getApplyType();
        log.info("[buyNow] buyNow come in, req: {}", JsonUtils.objectToJson(buyVO));
        String userUid = RequestHolder.getUserUid();
        if (StringUtils.isEmpty(userUid)) {
            throw new QueryException(Constants.USER_UID_EMPTY);
        }
        int userTag = RequestHolder.getUserTag();

        Date nowDate = new Date();
        if (null != buyVO.getEndTime() && buyVO.getEndTime().before(nowDate)) {
            throw new BusinessException("活动已结束！");
        }
        if(OrderApplyTypeEnum.LEADER.getCode().equals(applyType)){
            // 当前时间是否已经过了报名截止时间
            if (null != buyVO.getLeaderApplyEndTime() && buyVO.getLeaderApplyEndTime().before(nowDate)) {
                throw new BusinessException("领队报名已截止！");
            }
        }else{
            // 当前时间是否已经过了报名截止时间
            if (null != buyVO.getApplyEndTime() && buyVO.getApplyEndTime().before(nowDate)) {
                throw new BusinessException("报名已截止！");
            }
        }





        if(OrderApplyTypeEnum.LEADER.getCode().equals(applyType)) {
            // 已报名人数
//            Integer leaderAmount = payOrderService.getLeaderNumByResourceUid(buyVO.getResourceUid());
            // 校验总报名人数（已报名人数+本次报名人数）是否已超人数上限
            Integer allowLeaderNum = buyVO.getAllowLeaderNum();
            // 已报名领队人数
//            BigDecimal applyLeaderNum = amountMap.get(SQLConf.LEADER_AMOUNT) == null? BigDecimal.ZERO: (BigDecimal) amountMap.get(SQLConf.LEADER_AMOUNT);
            int applyLeaderNumInt = payOrderService.getLeaderNumByResourceUid(buyVO.getResourceUid());;
            // 已报名领队人数+本次报名人数 是否已超 人数上限
            if(applyLeaderNumInt + Constants.INTEGER_ONE > allowLeaderNum){
                throw new BusinessException("总领队人数超过上限，请减少领队人数或者刷新页面重新报名！");
            }
        }else {
            // 已报名人数
            Map<String, Object> amountMap = payOrderService.getApplyUserNumByResourceUid(buyVO.getResourceUid());
            // 校验总报名人数（已报名人数+本次报名人数）是否已超人数上限
            Integer allowPeopleNum = buyVO.getAllowPeopleNum();
            BigDecimal applyUserNum = amountMap.get(SQLConf.AMOUNT) == null? BigDecimal.ZERO: (BigDecimal) amountMap.get(SQLConf.AMOUNT);
            int applyUserNumInt = applyUserNum.intValue();
            // 已报名人数+本次报名人数 是否已超 人数上限
            if(applyUserNumInt + buyVO.getApplyUserNum() > allowPeopleNum){
                throw new BusinessException("总报名人数超过上限，请减少报名人数或者刷新页面重新报名！");
            }
        }
        // 获取资源类型
        ResourceTypeEnum resourceType = ResourceTypeEnum.getType(buyVO.getResourceType().getType());
        // 获取商品请求
        ProductRequest productRequest = new ProductRequest();
        productRequest.setResourceUid(buyVO.getResourceUid());
        productRequest.setResourceType(resourceType.getType());
        ProductDto productVO = new ProductDto();
        if(ResourceTypeEnum.RANK_MEMBER.equals(resourceType)){
            RankMemberEntity memberEntity = rankMemberService.getRankMemberById(productRequest.getResourceUid());

            if (memberEntity != null) {
                productVO = convertRankMember(memberEntity);
            }else {
                throw new QueryException("活动不存在，报名失败");
            }
            // 校验活动是否取消
            if(SwitchEnum.CLOSE.getCode().equals(memberEntity.getActivityStatus())){
                throw new QueryException("活动已取消，无法报名");
            }
        }

        // 判断用户是否购买该商品
        QueryWrapper<PayOrderEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SQLConf.CREATE_USER_UID, userUid);
        queryWrapper.eq(SQLConf.RESOURCE_UID, productVO.getResourceUid());
        queryWrapper.eq(SQLConf.RESOURCE_TYPE, productVO.getResourceType());
        // 同一个人不能同时报名领队和玩家，所以下面的注释掉
//        queryWrapper.eq(SQLConf.APPLY_TYPE, applyType);
        queryWrapper.last(SysConf.LIMIT_ONE);
        queryWrapper.orderByDesc(SQLConf.CREATE_TIME);
        PayOrderEntity payOrder = payOrderService.getOne(queryWrapper);

        // 如果订单存在，需要判断是否完成支付
        boolean buildOrder = true;
        if (payOrder != null) {
            if (OrderStatusEnum.PaySuccess.equals(payOrder.getOrderStatus())) {
                throw new QueryException("已经存在报名订单，您可以取消原订单并重新下单！");
            }
            // 还存在未支付的订单，需要重新走创建流程
            if (OrderStatusEnum.New.equals(payOrder.getOrderStatus())) {
                buildOrder = false;
            }
        }

        // 调用支付接口，进行支付处理
        PayMethodEnum payMethod = buyVO.getPayMethod();
        // 客户端
        String client = buyVO.getClient();

        // 判断是否是折扣商品
        BigDecimal price = buyVO.getPrice();
        // price乘以报名人数等于订单金额（元）
        BigDecimal totalPrice = price.multiply(new BigDecimal(buyVO.getApplyUserNum()));
        // 折扣商品，需要判断是否在折扣区间
        if (ChargeTypeEnum.Discount.getType() == productVO.getChargeType()) {
            if (productVO.getDiscountStartTime() == null || productVO.getDiscountEndTime() == null) {
                // 判断是否设置折扣时间
            } else {
                // 判断是否命中折扣时间
                boolean checkIn = DateUtils.checkNowBetweenIn(productVO.getDiscountStartTime(), productVO.getDiscountEndTime());
                if (checkIn) {
                    price = productVO.getDiscountPrice();
                }
            }
        } else if (ChargeTypeEnum.VIP_Free.getType() == productVO.getChargeType()) {
            // 判断是否是会员，如果是会员，价格为0元，非会员正常价
            if (userTag >= 1) {
                price = BigDecimal.ZERO;
            }
        }

        // 如果订单为空，则需要创建订单
        if (buildOrder) {
            log.info("[buyNow] 订单不存在，重新创建");
            payOrder = new PayOrderEntity();
            payOrder.setOrderNo(idGenerator.snowflakeId() + "");
            payOrder.setApplyType(applyType);
            payOrder.setCreateUserUid(userUid);
            // TODO.mo 代理分账，需要设置分账人
            payOrder.setMerchantUserUid("");
            payOrder.setResourceUid(productVO.getResourceUid());
            payOrder.setResourceOid(productVO.getResourceOid());
            payOrder.setResourceType(productVO.getResourceType());

            payOrder.setTotalPrice(totalPrice);
            payOrder.setProductPrice(price);
            payOrder.setTitle(productVO.getName());
            payOrder.setSummary(productVO.getSummary());
            payOrder.setSnapshot(JsonUtils.objectToJson(productVO));
            payOrder.setPayMethod(payMethod.getType());
            // buyVO中的数据转移到 payOrder
            setPayOrderFromBuyVO(buyVO, payOrder);
            // 0元订单或者支付方式为"私下转账"，订单状态直接变成已完成
            if (price.compareTo(BigDecimal.ZERO) == 0 || PayMethodEnum.PRIVATE_TRANSFER.equals(payMethod)) {
                payOrder.setOrderStatus(OrderStatusEnum.PaySuccess);
            } else {
                payOrder.setOrderStatus(OrderStatusEnum.New);
            }
            boolean isSave = payOrder.insert();
            if (!isSave) {
                log.error("[buyNow] 更新订单失败");
                throw new QueryException("更新订单失败");
            }
        } else {
            log.info("[buyNow] 重新设置订单价格");
            payOrder.setTotalPrice(totalPrice);
            payOrder.setProductPrice(price);
            // 0元订单或者支付方式为"私下转账"，订单状态直接变成已完成
            if (price.compareTo(BigDecimal.ZERO) == 0  || PayMethodEnum.PRIVATE_TRANSFER.equals(payMethod)) {
                payOrder.setOrderStatus(OrderStatusEnum.PaySuccess);
            } else {
                payOrder.setOrderStatus(OrderStatusEnum.New);
            }
            if(payMethod != null) {
                payOrder.setPayMethod(payMethod.getType());
            }
            // buyVO中的数据转移到 payOrder
            setPayOrderFromBuyVO(buyVO, payOrder);
            payOrder.updateById();
        }
        payOrder.setOrganizerUserUid(productVO.getUserUid());
        // 支付方式为"私下转账"，订单状态直接变成已完成
        if (PayMethodEnum.PRIVATE_TRANSFER.equals(payMethod)) {
            // 订单创建成功
            PayOrderDto dto = new PayOrderDto();
            BeanUtils.copyProperties(payOrder, dto);
            domainEventUtil.publishEvent(EventAction.ORDER_PAY_SUCCESS, dto);

            return ResultUtil.successWithData(payOrder.getUid());
        }

        // 0元订单，订单状态直接变成已完成
        if (price.compareTo(BigDecimal.ZERO) == 0) {
            // 订单支付成功
            PayOrderDto dto = new PayOrderDto();
            BeanUtils.copyProperties(payOrder, dto);
            domainEventUtil.publishEvent(EventAction.ORDER_PAY_SUCCESS, payOrder);
            return ResultUtil.successWithMessage("支付成功");
        }
        // 蓝兔支付中的微信支付且client是小程序，订单状态为新建，返回订单号，作为请求蓝兔支付的参数
        if (PayMethodEnum.LANTU_WECHAT_PAY.equals(payMethod) && SysConf.MINI.equals(client)) {
            // 订单创建成功
            PayOrderDto dto = new PayOrderDto();
            BeanUtils.copyProperties(payOrder, dto);
            domainEventUtil.publishEvent(EventAction.ORDER_CREATE_SUCCESS, dto);
            dto.setTimestamp(String.valueOf(System.currentTimeMillis()/1000));
            dto.setNotifyUrl(lanTuWxPayBean.getDomain().concat(LANTU_NOTIFY_URL));
//            dto.setNotifyUrl("https://eurapi.suyun999.com"+LANTU_NOTIFY_URL);
            dto.setMchId(lanTuWxPayBean.getMchId());
            dto.setSign(LantuPayUtil.createSignByOrder(dto));

            return ResultUtil.successWithData(dto);
        }
        // 蓝兔支付中的公众号支付，请求蓝兔的公众号支付
        if (PayMethodEnum.LANTU_WECHAT_JS_PAY.equals(payMethod) && SysConf.H5.equals(client)) {
            // 这里还是使用 LANTU_WECHAT_PAY 对应的sevice类去处理 jsPay
            return PayServiceFactory.getPayService(PayMethodEnum.LANTU_WECHAT_PAY).jsPay(payOrder.getUid(), buyVO.getReturnUrl());
        }
        return PayServiceFactory.getPayService(payMethod).pay(payOrder.getUid());
    }

    /**
     *  buyVO中的数据转移到 productVO
     */
    private void setPayOrderFromBuyVO(BuyVO buyVO, PayOrderEntity payOrder) {
        payOrder.setApplyUserName(buyVO.getApplyUserName());
        payOrder.setIdCard(buyVO.getIdCard());
        payOrder.setGender(buyVO.getGender());
        payOrder.setPhone(buyVO.getPhone());
        payOrder.setWeChat(buyVO.getWeChat());
        payOrder.setAge(buyVO.getAge());
        payOrder.setRemark(buyVO.getRemark());
        if(OrderApplyTypeEnum.LEADER.getCode().equals(buyVO.getApplyType())) {
            payOrder.setApplyUserNum(Constants.INTEGER_ZERO);
        }else {
            payOrder.setApplyUserNum(buyVO.getApplyUserNum());
        }
    }

    public ProductDto convertRankMember(RankMemberEntity rankMemberEntity) {
        if (rankMemberEntity == null) {
            return null;
        }
        ProductDto productVO = new ProductDto();
        productVO.setName(rankMemberEntity.getTitle());
        productVO.setSummary(rankMemberEntity.getSummary());
//        productVO.setPrice(rankMemberDto.getPrice());
        productVO.setResourceType(ResourceTypeEnum.RANK_MEMBER.getType());
        productVO.setResourceUid(rankMemberEntity.getUid());
        productVO.setResourceOid(rankMemberEntity.getOid());
        productVO.setPhotoUrl(rankMemberEntity.getPhotoUrl());
        productVO.setUserUid(rankMemberEntity.getCreateUserUid());
//        productVO.setDiscountStartTime(mediaInfo.getDiscountStartTime());
//        productVO.setDiscountEndTime(mediaInfo.getDiscountEndTime());
//        productVO.setDiscountPrice(rankMemberDto.getPrice());
        productVO.setChargeType(ChargeTypeEnum.Normal.getType());
        return productVO;
    }

    @Override
    public String sponsor(SponsorVO sponsorVO) {
        log.info("[sponsor] sponsor come in, req: {}", JsonUtils.objectToJson(sponsorVO));
        String userUid = RequestHolder.getUserUid();
        if (StringUtils.isEmpty(userUid)) {
            throw new InsertException("用户暂未登录，请先登录后再操作吧~");
        }
        if (sponsorVO.getPrice() <= 0) {
            throw new InsertException("赞助金额不能为空");
        }
        // 查询用户下未支付的订单
        QueryWrapper<PayOrderEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SQLConf.USER_UID, userUid);
        queryWrapper.eq(SQLConf.RESOURCE_TYPE, ResourceTypeEnum.SPONSOR.getType());
        queryWrapper.eq(SQLConf.ORDER_STATUS, OrderStatusEnum.New);
        queryWrapper.last(SysConf.LIMIT_ONE);
        queryWrapper.orderByDesc(SQLConf.CREATE_TIME);
        PayOrderEntity payOrder = payOrderService.getOne(queryWrapper);

        // 价格不一致，判断是否需要生成订单
        boolean buildOrder = true;
        if (payOrder != null) {
            long price = sponsorVO.getPrice().longValue();
            // 如果价格不同，需要重新生成订单ID
            if (price == payOrder.getTotalPrice().longValue()) {
                buildOrder = false;
            }
        }

        if (payOrder == null || buildOrder) {
            // 没有历史订单，重新构建生成
            payOrder = new PayOrderEntity();
            payOrder.setCreateUserUid(userUid);
            // TODO.mo 代理分账，需要设置分账人
            payOrder.setMerchantUserUid("");
            payOrder.setResourceUid(StringUtils.getUUID());
            payOrder.setResourceType(ResourceTypeEnum.SPONSOR.getType());
            payOrder.setTotalPrice(BigDecimal.valueOf(sponsorVO.getPrice()).setScale(2,BigDecimal.ROUND_HALF_UP));
            payOrder.setPayType(PayTypeEnum.CASH_PAY.getType());
            payOrder.setPayMethod(PayMethodEnum.YUN_GOU_OS_WECHAT_PAY.getType()); // 目前只接入了第三方微信支付，写死
            payOrder.setProductPrice(BigDecimal.valueOf(sponsorVO.getPrice()).setScale(2,BigDecimal.ROUND_HALF_UP));
            payOrder.setTitle("社区网站赞助");
            payOrder.setSummary("社区网站赞助");
            payOrder.setOrderStatus(OrderStatusEnum.New);
            boolean isSave = payOrder.insert();
            if (!isSave) {
                log.error("[buyNow] 更新订单失败");
                throw new QueryException("更新订单失败");
            }
        }
        return PayServiceFactory.getPayService(PayMethodEnum.YUN_GOU_OS_WECHAT_PAY).pay(payOrder.getUid());
    }

    @Override
    public Boolean closePayOrder(int hour) {
        QueryWrapper<PayOrderEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SQLConf.ORDER_STATUS, OrderStatusEnum.New);
        Date beforeDate = new Date(System.currentTimeMillis() - hour * 60 * 60 * 1000L);
        queryWrapper.le(SQLConf.CREATE_TIME, beforeDate);
        List<PayOrderEntity> payOrderList = payOrderService.list(queryWrapper);
        if (payOrderList.size() == 0) {
            return true;
        }
        // 调度对应实现，去关闭订单
        for (PayOrderEntity payOrder : payOrderList) {
            try {
                PayMethodEnum payMethod = PayMethodEnum.getPayMethod(payOrder.getPayMethod());
                PayServiceFactory.getPayService(payMethod).closePayOrder(payOrder);
            } catch (Exception e) {
                log.error(e.getMessage());
            } finally {

            }
        }
        return true;
    }
}
